Web開發學習筆記11 — DOM、Attribute與Property的差異


Posted by Teagan Hsu on 2020-12-28

文件物件模型(Document Object Model, DOM)是什麼?

簡單來說就是將每個HTML的標籤都物件化,讓JavaScript可以訪問和更改HTML的元素,舉例來說,我們可以點擊按鈕來改變文字。當網頁載入時,瀏覽器會自動幫我們創立這個頁面的DOM。

為何我們需要DOM?

在以前瀏覽器大亂之時,每家瀏覽器的規則都不一樣,讓工程師非常頭疼,直到W3C訂立出了DOM的標準,讓瀏覽器公司可以依照這個準則去設計瀏覽器。

DOM tree與節點(node)

DOM將標籤定義成物件後,會形成一個樹狀結構,也就是DOM tree。
這是我們的HTML檔:

表示為DOM tree後會變成這樣,每個標籤就是一個節點,最上層的是Document,往下延伸出Element,再往下還有TextAttribute

Selecting DOM Elements

  1. getElementById:根據元素ID選取。
  2. getElementsByTagName:根據標籤名稱選取。(例如< p >、< h1 >....)
  3. getElementsByClassName:根據Class選取。
  4. getElementsByName:根據Name選取。
  5. querySelector(selectors):根據selectors選取。(可使用範圍很廣)

HTMLCollection

HTMLCollection是元素(Element)的集合,並提供可選取集合成員的方法與屬性。
如果我們使用getElementById去選取h1,console中會出現HTMLCollection,它看起來長得有點像Array(有length屬性和長得像index的item()),但實質上它是Object,所以不能用陣列方法處理(像是map()filter()...),但用for可以遍歷。

NodeList

NodeList也是物件,是節點的集合。不像是HTMLCollection只能儲存Element,NodeList同時包含了TextAttribute...等等。可以看到圖片上NodeListHTMLCollection多包涵了6個Text

如何得到HTMLCollection和NodeList物件?

  • HTMLCollection:childrengetElementsByTagName()
  • NodeList:childNodesquerySelectorAll()

注意:

  • 使用childNodes回傳的NodeList為動態集合(live collection)。
  • 使用querySelectorAll()回傳的NodeList為靜態集合(static collection)。
  • HTMLCollection具有即時性(live),如果document物件發生改變,HTMLCollection物件也會跟著做變化。

textContent與innerText

textContentinnerText皆是DOM的屬性,兩者名字很像,容易混淆。
差異:

textContent

  • 標準化用法
  • get所有元素的內容,包含<script><style>元素
  • 返回每個節點的元素

innerText

  • 非標準化用法
  • 只顯示“人眼可見”的元素,隱藏的內容不會顯示出來。
  • 在計算中加入了CSS樣式,知道Styling長怎樣,但也會造成應用程序下降

示範textContent與innerText的差異結果,使用以下HTML:

<body>

    <p id='para'>
        <style>
            #para {
                color: blue
            }
        </style>
        HI!!!!!!<br>I'm your new classmate</p>

    <h4>textContent:</h4>
    <textarea id="textContent" rows="4" cols="20" readonly>...</textarea>
    <h4>innerText:</h4>
    <textarea id="innerText" rows="4" cols="20" readonly>...</textarea>

</body>

使用以下JavaScript:

let para = document.querySelector('#para');
let textContent = document.querySelector('#textContent');
let innerText = document.querySelector('#innerText');

//textContent顯示:
textContent.value = para.textContent;
<!--"

            #para {
                color: blue
            }

        HI!!!!!!I'm your new classmate"-->


//innerText顯示:
innerText.value = para.innerText;
<!--"HI!!!!!!
I'm your new classmate"-->

頁面顯示結果:

Attribute與Property的差別

當瀏覽器加載頁面時,它會解析HTML並從中生成DOM property。 大多數形況下,HTML attribute會自動成為DOM property。
舉例來說,如果tag為<div class = 'introduction'>,則DOM property也會具有div.class = 'introduction'
但是必須注意attribute與property的映射不是一對一的,下面會詳細介紹它們的相異之處。

Attributes
Attributes是我們寫在HTML的屬性,像是<div type = 'text'>
Properties
Properties是存在在DOM objects中的屬性,像是div.type

Attribute要符合相對應的Element class

當我們的element有符合標準的的attribute時,相對應的property就會生成。但是當element不符合標準時,相對應的property就不會生成。
像是input元素有type這個attribute(符合標準),但body元素沒有type(不符合標準),所以不會生成相應的property。

那我們要如何取得不符合標準的attribute呢?

以下有幾種方法:

  • el.hasAttribute() - 檢查這個attribute有沒有存在
  • el.getAttribute() - 取得attribute
  • el.setAttribute() - 設定attribute的value
  • el.removeAttribute() - 移除attribute
  • el.attributes - 將該元素所有attribute的節點返回為一個集合

通常Attribute與Property的之間是同步的

通常Attribute與Property的之間是同步的,意思是說當一個標準的attribute變更,與它相對應的property也會自動更新。
以下範例:

//attribute => property

let p = document.querySelector('p');
p.setAttribute('id', 'paragraph');
p.id;    //"paragraph"

//property => attribute
p.id = 'newParagraph';
p.getAttribute('id');    //"newParagraph"

但也有例外的情況,像input.value只能同步attribute => property。

<input id = 'input' type = 'password'>Password

<script>
//attribute => property
input.setAttribute('value', 'password');
input.value;    //password

//property =X> attribute
input.value = 'newPassword';
input.getAttribute('value');    //password(沒有更新成newPassword)

</script>

DOM property的值通常為string但也有例外的狀況,例如:當利用element.property取得style屬性時是回傳object,另一種情況:用element.getAttribute取得style的屬性時,會回傳string。

<body id="body" style="background-color:#000;">
</body>

<script>
console.log(body.getAttribute('style'));
//background-color:#000;

console.log(document.body.style);
//CSSStyleDeclaration {0: "background-color", alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: "", …}
</script>

相同概念的舉例,input.checked的property是回傳boolean值,而使用getAttribute則會回傳空字串。

<input id = "input" type = "checkbox" checked>Check Box

<script>
console.log(input.getAttribute('checked'));  //empty string
console.log(input.checked);   //true
</script>

上述提到property大多為string。但少數情形下,儘管property的type是string,attribute也不一定是string。
經典的例子就是URL,看以下的例子可以發現element.href回傳的都是完整URL。這是因為
W3C的規定,href property一定要是完整形式的連結。

<a href='/Users/teagan/Desktop/DOM.html'>DOM</a>
<a href='#1'>first-paragraph</a>

<script>
//選取第一個a連結
let dom = document.querySelectorAll('a')[0];

console.log(dom.getAttribute('href'));
// /Users/teagan/Desktop/DOM.html

console.log(dom.href);
// file:///Users/teagan/Desktop/DOM.html


//選取第二個a連結
let google = document.querySelectorAll('a')[1];

console.log(google.getAttribute('href'))'
// #1

console.log(google.href);
// file:///Users/teagan/Desktop/DOM.html#1
</script>

非標準屬性、數據

有時我們使用非標準屬性去自定義數據,或是為JavaScript標記(mark)HTML元素。
注意,使用data-*來自定義屬性,這讓JS或CSS更加容易讀取屬性的值。

範例一:取得屬性的值

<body id="body" data-product-category="noodles">

<script>
//使用element.dataset.property取得(注意-(dash)要轉換成camelCase
console.log(document.body.dataset.productCategory)  //noodles

//或使用getAttribute
console.log(document.body.getAttribute('data-product-category'))  //noodles
</script>

範例二:變更字的顏色與內容

<div class="order" data-order-state="new">
  A new order.
</div>
<style>
  .order[data-order-state="new"] {
    color: black;
  }

  .order[data-order-state="pending"] {
    color: green;
  }
</style>
<script>
order.dataset.orderState = "pending";
let padding = document.querySelector('.order');
padding.textContent = 'A padding order';
</script>

執行JS會改變字的顏色與內容:


參考資料:

  1. Using data attributes - MDN
  2. getAttribute() versus Element object properties?
  3. Attributes and properties - javascript.info
  4. Difference between textContent vs innerText
  5. DOM
  6. HTMLCollection與NodeList
  7. HTMLCollection - MDN
  8. NodeList - MDN

#javascript #DOM #Attribute #Property







Related Posts

Day 06 遠交近攻

Day 06 遠交近攻

Avoid blocking by navigation menu on mobile device

Avoid blocking by navigation menu on mobile device

作業 14 週、筆記

作業 14 週、筆記


Comments